package com.calvin.study.multithread.threadpool;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 本来主要讲解线程池 submit的用法，返回值。 submit方法中定义了参数，分别是Callable<T>,Runnable
 * 
 * public interface Callalbe<V>{ V call() throws Exception; }
 * 
 * interface Runnable(){ public abstract void run(); }
 * 
 * Callable能接受一个泛型，然后在call方法中返回一个这个类型的值。而Runnable的run方法没有返回值
 * Callable的call方法可以抛出异常，而Runnable的run方法不会抛出异常。
 *
 * Future也是一个接口，通过他可以获得任务执行的返回值。
 */
public class ThreadPoolDemo03 extends BaseThreadPool {
	static ExecutorService executor = getInstance();

	/**
	 * get()方法默认是阻塞的，一直要等待任务执行完成（3s），拿到了返回结果，主线程才会继续运行。
	 */
	public static void test1() throws InterruptedException, ExecutionException {

		System.out.println("执行任务之前：" + getDateStr());
		Future<String> future = executor.submit(new Callable<String>() {
			@Override
			public String call() throws Exception {
				// 假设执行业务所需时间
				Thread.sleep(3000);
				System.out.println("call方法执行了");
				return "call方法返回值";
			}
		});
		System.out.println("执行任务之后，获取返回结果之前：" + getDateStr());
		System.out.println("获取返结果：" + future.get());
		System.out.println("获取到返回结果之后" + getDateStr());
	}

	/**
	 * 由test1()得知，get()方法是阻塞的，需要等到任务执行完成后才能获取返回值。
	 * 
	 * 如下，task2执行所需3秒，task1执行所需5秒。 获取第一个结果阻塞的5秒，而第二个结果（3秒）完成，所以第二个结果可以立即获取
	 * 
	 */
	public static void test2() throws InterruptedException, ExecutionException {
		Future<String> f1 = executor.submit(new Callable<String>() {
			@Override
			public String call() throws Exception {
				// 业务所需时间
				Thread.sleep(5000);
				System.out.println("task1方法执行");
				return "task1执行完了";
			}

		});

		Future<String> f2 = executor.submit(new Callable<String>() {
			@Override
			public String call() throws Exception {
				// 业务所需时间
				Thread.sleep(3000);
				System.out.println("task2方法执行");
				return "task2执行完了";
			}
		});

		System.out.println("提交任务之后 " + getDateStr());
		System.out.println("开始获取第一个返回值 " + getDateStr());
		System.out.println("获取返回值: " + f1.get());
		System.out.println("获取第一个返回值结束，开始获取第二个返回值 " + getDateStr());
		System.out.println("获取返回值2: " + f2.get());
		System.out.println("获取第二个返回值结束 " + getDateStr());
	}

	/**
	 * get()方法设置超时时间，避免长时间等待。
	 * 如果执行时间大于超时时间，则抛出异常，异常可以被主程序（main）捕获
	 */
	public static void test3() throws InterruptedException, ExecutionException, TimeoutException, Exception {
		Future<String> f1 = executor.submit(new Callable<String>() {
			@Override
			public String call() throws Exception {
				// 业务所需时间
				Thread.sleep(5000);
				System.out.println("task1方法执行");
				return "task1执行完了";
			}

		});
		System.out.println(f1.get(3, TimeUnit.SECONDS));
		executor.shutdown();

	}
	
	public static void test4() throws InterruptedException, ExecutionException {
		Future<String> r = executor.submit(new Callable<String>() {
			@Override
			public String call() throws Exception {
				Thread.sleep(500);
				return getCurThreadName() + "任务执行完成";
			}
		});
		System.out.println(r.get());
		executor.shutdown();
	}

	public static void main(String[] args) {
		try {
			for(int i=0,len=45;i<=len;i++) {
				Future<String> r = executor.submit(new Callable<String>() {
					@Override
					public String call() throws Exception {
						Thread.sleep(500);
						System.out.println(getCurThreadName() + "任务执行完成");
						return getCurThreadName() + "任务执行完成";
					}
				});
			}
			executor.shutdown();
			//test3();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}

}
